package be.ipl.streams.daoimpl;

import java.lang.reflect.ParameterizedType;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.NonUniqueResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.TemporalType;
import javax.persistence.TypedQuery;

import be.ipl.streams.dao.Dao;

public class DaoImpl<E> implements Dao<E> {

	private Class<E> entityClass;
	
	@PersistenceContext(unitName = "streams")
	private EntityManager entityManager;
	
	@SuppressWarnings("unchecked")
	public DaoImpl() {
		ParameterizedType genericSuperclass = (ParameterizedType) getClass()
				.getGenericSuperclass();
		this.entityClass = (Class<E>) genericSuperclass
				.getActualTypeArguments()[0];
	}
	
	@Override
	public E register(E entity) {
		entityManager.persist(entity);
		return entity ;
	}

	@Override
	public E update(E entity) {
		return entityManager.merge(entity);
	}

	@Override
	public E refresh(int id) {
		E entity = research(id);
		entityManager.refresh(entity);
		return entity;
	}

	@Override
	public E research(int id) {
		return (E) entityManager.find(entityClass, id);
	}

	@Override
	public List<E> list() {
		return list("select e from " + entityClass.getName() + " e");
	}
	

	protected List<E> list(String queryString, Object... params) {
		List<E> entity = null;
		TypedQuery<E> query = entityManager.createQuery(queryString, entityClass);
		int i = 0, j = 1;
		while(i < params.length) {
			if (params[i] instanceof Date ) {
				query.setParameter(j, (Date)params[i], (TemporalType) params[i+1]);
				i+=2; 
			} else if (params[i] instanceof Calendar) {
				query.setParameter(j, (Calendar)params[i], (TemporalType) params[i+1]);
				i+=2; 
			} else {
				query.setParameter(j, params[i]);
				i++; 
			}
			j++;
		}
		entity = query.getResultList();
		return entity;
	}
	
	protected E recherche(String queryString, Object... params) {
		try {
			TypedQuery<E> query = entityManager.createQuery(queryString, entityClass);
			int i = 0, j = 1;
			while(i < params.length) {
				if (params[i] instanceof Date ) {
					query.setParameter(j, (Date)params[i], (TemporalType) params[i+1]);
					i+=2; 
				} else if (params[i] instanceof Calendar) {
					query.setParameter(j, (Calendar)params[i], (TemporalType) params[i+1]);
					i+=2; 
				} else {
					query.setParameter(j, params[i]);
					i++; 
				}
				j++;
			}
			return (E) query.getSingleResult();
		} catch (NoResultException e) {
			return null;
		} catch (NonUniqueResultException e) {
			return null; // throw new InternalError();
		}
	}

}
